import pandas as pd
import numpy as np
import math
import warnings
warnings.filterwarnings("ignore")
import datetime

starttime = datetime.datetime.now()

data = pd.read_csv('SA_data_50000.csv')

fuzzy_fac_dict = {'5.0': (1, 0, 0, 0, 0), '4.5': (0.8, 0.2, 0, 0, 0),
                  '4.0': (0.3, 0.6, 0.1, 0, 0), '3.5': (0.1, 0.5, 0.4, 0, 0),
                  '3.0': (0, 0.25, 0.5, 0.25, 0), '2.5': (0, 0, 0.2, 0.6, 0.2),
                  '2.0': (0, 0, 0.1, 0.7, 0.2), '1.5': (0, 0, 0, 0.2, 0.8),
                  '1.0': (0, 0, 0, 0, 1), '0.5': (0, 0, 0, 0, 1)}

print(fuzzy_fac_dict)

movie_count = np.array(data)[6]  # 用于下面计算电影的个数
data_ture = 0  # 计算预测正确的个数
data_false = 0  # 计算预测错误的个数
print(np.array(data)[0][1: -1])
for index in range(0, len(data)):
    user = np.array(data)[index]

    # 计算相似度
    sim = []
    sim_count = []  # 记录两个用户之间看过多少部相同的电影
    for i in range(len(data)):
        use_da = np.array(data)[i]
        S_sum = []
        count = 0
        for j in range(1, len(movie_count)):
            label = str(use_da[j])  # data的列索引从1开始
            label_act = str(user[j])  # active user的列索引从0开始
            if str(label) == 'nan' or str(label_act) == 'nan':
                continue
            label_fac = fuzzy_fac_dict[label]
            label_act_fac = fuzzy_fac_dict[label_act]
            S = 1-(1/(5**0.5))*((math.pow((label_fac[0]-label_act_fac[0]), 2)+math.pow((label_fac[1]-label_act_fac[1]), 2) +
                                 math.pow((label_fac[2]-label_act_fac[2]), 2)+math.pow((label_fac[3]-label_act_fac[3]), 2) +
                                 math.pow((label_fac[4]-label_act_fac[4]), 2))**0.5)
            S_sum.append(S)
            count = count + 1
        sim.append(np.mean(S_sum))
        sim_count.append(count)

    use = data['userId']
    simi_user = pd.concat([pd.DataFrame(use), pd.DataFrame(sim)], axis=1)
    simi_user = simi_user.rename(columns={0: 'similarity'})
    simi_user = pd.concat([simi_user, pd.DataFrame(sim_count)], axis=1)
    simi_user = simi_user.rename(columns={0: 'count'})
    simi_user = simi_user.sort_values(by="similarity", ascending=False)

    simi_user = (simi_user.loc[simi_user['count'] > 5])  # 只显示两个用户看过的相同电影数大于5的相似度
    print(simi_user)

    # 选择相似度前四的用户
    user0, user1, user2, user3 = simi_user['similarity'][1: 5]
    userId0, userId1, userId2, userId3 = simi_user['userId'][1: 5]
    print("跟当前用户最相似的前四位用户分别为：")
    print(userId0, userId1, userId2, userId3)  # 打印出跟当前用户最相似的前四位用户
    user0_w = user0 / (user0 + user1 + user2 + user3)
    user1_w = user1 / (user0 + user1 + user2 + user3)
    user2_w = user2 / (user0 + user1 + user2 + user3)
    user3_w = user3 / (user0 + user1 + user2 + user3)
    W = np.array([user0_w, user1_w, user2_w, user3_w])
    # print(W)

    for k in range(1, len(movie_count)):
        label_userId0 = str(np.array(data)[userId0-1][k])  # 第userId0位用户对第k个电影的评分
        label_userId1 = str(np.array(data)[userId1-1][k])
        label_userId2 = str(np.array(data)[userId2-1][k])
        label_userId3 = str(np.array(data)[userId3-1][k])
        label_userId4 = str(user[k])  # 现在的用户
        # print(label_userId4, label_userId0, label_userId1, label_userId2, label_userId3)
        # 只对当前的用户以及跟他最相似的前四位用户都看过的电影进行预测
        if str(label_userId0) == 'nan' or str(label_userId1) == 'nan' or str(label_userId2) == 'nan' or\
                str(label_userId3) == 'nan' or str(label_userId4) == 'nan':
            continue
        print("当前的电影id为：")
        print(data.columns[k])  # 打印当前电影的id
        label_userId0_fac = fuzzy_fac_dict[label_userId0]
        label_userId1_fac = fuzzy_fac_dict[label_userId1]
        label_userId2_fac = fuzzy_fac_dict[label_userId2]
        label_userId3_fac = fuzzy_fac_dict[label_userId3]
        pre_matrix = np.array([label_userId0_fac, label_userId1_fac, label_userId2_fac, label_userId3_fac])
        Y = np.dot(W, pre_matrix)
        # print(Y)
        Y_ = (Y[0] * 5 + Y[1] * 4 + Y[2] * 3 + Y[3] * 2 + Y[4] * 1) / sum(Y)
        print("预测的评分：")
        print(Y_)
        use_a = np.array(data)[index][k]
        print("真实的评分：")
        print(use_a)
        if Y_ >= 3.5 and use_a >= 3.5:
            data_ture = data_ture + 1
        if Y_ < 3.5 and use_a < 3.5:
            data_ture = data_ture + 1
        if Y_ >= 3.5 and use_a < 3.5:
            data_false = data_false + 1
        if Y_ < 3.5 and use_a >= 3.5:
            data_false = data_false + 1
        print('data_ture:', data_ture)  # 预测正确的个数
        print('data_false:', data_false)  # 预测错误的个数
accuracy = data_ture / (data_ture + data_false)
print(accuracy)
endtime = datetime.datetime.now()

print(endtime - starttime)

